'''
1、环境搭建说明：测试模块为OPEN的版本需要./test_sdk_api在data目录下

    需要设置项：设置模块的debug口和AT口
                   
2、脚本运行逻辑：
        1.关注modem reset次数,模块AT口发送AT+QMSSRR=2,之后接口设置modem重启
        2.关注重启后查询modem状态，是否引起整机重启，查询IMEI号
        3.触发modem reset后，关注AT口是否能正常通信，持续关注cpu占用值，是否有持续占用较高的情况（目前脚本关注重启后一分钟的cpu占用率，可以自行修改）
3、使用未占满cpu版本调试
4、版本RN：
	v1.0：首次编写
'''

import serial
import time
import os
import sys
import random
import re

# 定义常量
DEBUG_PORT = "COM4"
AT_PORT = "COM9"
BAUDRATE = 115200
# 定义变量
at_serial = None
debug_serial = None
#记录运行次数
runTimes		= 0
#log文件
DEBUG_LOG = ""


# 创建日志文件
def createLogFile():
    global DEBUG_LOG
    timestamp = time.strftime("%Y-%m-%d_%H_%M_%S", time.localtime())
    DEBUG_LOG = f"DEBUG_LOG_{timestamp}.log"
    
    # 创建日志文件时，指定编码为 utf-8
    with open(DEBUG_LOG, 'w', encoding='utf-8') as file:
        file.write("日志开始记录...\n")

# 日志写入函数
def write_log(log, logFile=""):
    # 打开文件时指定编码为 utf-8
    with open(logFile, 'a', encoding='utf-8') as file_object:
        file_object.write(str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + "\r\n" + log + "\r\n")
    print(log)


#发送at指令
def at_write(command, timeout, DEBUG_PORT_opened, at_result,RDY=0,CPIN=0):
 write_log(str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())),DEBUG_LOG)
 at_command = command.encode("UTF-8")
 DEBUG_PORT_opened.write(at_command)

#读取at口返回
def at_read(serial_port, logFile=""):
 rec_str = ''
 while (True):
  time.sleep(1)
  lenth = serial_port.inWaiting()
  if lenth > 0:
   rec_str = serial_port.read(size=lenth)
   try:
    rec_str = re.sub('\\x1b.*?m', "", rec_str.decode("UTF-8"), 0, re.I)
    if logFile != "":
     with open(logFile, 'a') as file_object:
      rec_str = str(time.time()) + ":" + str(
       time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + "\r\n" + rec_str
      file_object.write(
       str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + "\r\n" + rec_str + "\r\n")
    return rec_str
   except:
    return ""
  else:
   break
 return rec_str

# 登录设备
def loginDevice():
 global DEBUG_LOG
 #确认登录失败的条件，或者，不可能失败
 while True:
  print("等待登录... ... ")
  time.sleep(3)
  at_write("\r\n",3,debug_serial,"OK")
  result = at_read(debug_serial)

  with open(DEBUG_LOG, 'a') as file_object:
   file_object.write(result)

  if "login:" in result:
   at_write("root\r\n",3,debug_serial,"OK")
   print("账号输入成功")
   time.sleep(2)
   at_write("oelinux123\r\n",3,debug_serial,"OK")
   print("密码输入成功")
  elif "~ #" in result:
   print("登录成功")
   at_write("echo 2 >/proc/sys/kernel/printk\r\n",3,debug_serial,"OK")
   break
  else:
   continue 

#检查debug口通信状态
def check_port_status():
 global debug_serial
 if debug_serial == None:
  try:
   debug_serial = serial.Serial(DEBUG_PORT,BAUDRATE)
  except:
   print("at口连接失败，请检查端口")
   sys.exit()

# 写入运行次数到日志
def writeRuntimesToLog():
 global runTimes
 with open(DEBUG_LOG, 'a+') as file_object:
  file_object.write("\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes,">"*20))
 print("\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes,">"*20))
 runTimes += 1

# 进入测试接口
def intoTestInterface_testsdk(debug_serial,logFile):
 at_write("cd /data\r\n./test_sdk_api\r\n",3,debug_serial,"OK")
 result = at_read(debug_serial,logFile)

# 退出测试接口
def exit_testsdk(debug_serial,logFile):
 at_write("-1\n-1\n",3,debug_serial,"OK")
 result = at_read(debug_serial,logFile)

# 返回测试接口
def back_testsdk(debug_serial,logFile):
 at_write("-1\n",3,debug_serial,"OK")
 result = at_read(debug_serial,logFile)


def set_at_command(command):
        # 打开串口
        ser = serial.Serial(AT_PORT, BAUDRATE)
        ser.write((command + "\r\n").encode())
        ser.write(("\r\n").encode())
        time.sleep(2)
        response_qmssr = ser.read_all().decode()
        ser.close()
        write_log(f"at指令{command}执行结果:{response_qmssr}",DEBUG_LOG)
        if 'OK' in response_qmssr:
            write_log(f"at指令{command}执行成功",DEBUG_LOG)
        else:
            write_log(f"at指令{command}执行失败",DEBUG_LOG)
def Serial_front_execution():
    at_write("echo 0 > /sys/class/subsys/subsys_modem/device/subsys0/system_reset_mode\r\n", 3 , debug_serial, "OK")
    time.sleep(3)
    at_write("sync\r\n", 3 , debug_serial, "OK")
    time.sleep(3)
    at_write("cat /sys/class/subsys/subsys_modem/device/subsys0/system_reset_mode\r\n", 3 , debug_serial, "OK")
    result = at_read(debug_serial,DEBUG_LOG)
    if "0" in result:
        write_log("修改成功",DEBUG_LOG)
    else:
        write_log("修改失败",DEBUG_LOG)
        sys.exit()
    time.sleep(3)
    set_at_command('AT+QMSSR=2')   #设置QMSSR=2
    at_write("cat /sys/class/subsys/subsys_modem/device/subsys0/crash_count\r\n", 3 , debug_serial, "OK")
    result = at_read(debug_serial)
    t = result.split("count")[1]
    print("modem reset次数为:",t)
    time.sleep(1)
def modem_reset():
    # 获取初始PID
    at_write("pgrep mcm_ril_servic\r\n", 3, debug_serial, "OK")
    mcm_ril_servic_PID1 = at_read(debug_serial, DEBUG_LOG)
    time.sleep(1)
    at_write("pgrep ql_netd\r\n", 3, debug_serial, "OK")
    ql_netd_PID1 = at_read(debug_serial, DEBUG_LOG)
    time.sleep(1)

    # 进入测试接口
    intoTestInterface_testsdk(debug_serial, DEBUG_LOG)
    time.sleep(1)

    # 运行测试SDK API
    at_write("7\r\n", 3, debug_serial, "OK")
    time.sleep(2)
    at_write("0\r\n", 3, debug_serial, "OK")
    time.sleep(2)
    at_write("6\r", 3, debug_serial, "OK")  # 设置重启modem回调
    time.sleep(2)
    at_write("1\r", 3, debug_serial, "OK")
    time.sleep(2)
    at_write("27\r", 3, debug_serial, "OK")  # 重启modem
    write_log("开始重启modem", DEBUG_LOG)
    time.sleep(25)
    result = at_read(debug_serial, DEBUG_LOG)

    # 检查重启状态
    if "OFFLINE" in result and "ONLINE" in result:
        write_log("modem重启成功", DEBUG_LOG)
    else:
        write_log("modem重启失败", DEBUG_LOG)
        sys.exit()
        
    # 进入测试接口
    intoTestInterface_testsdk(debug_serial, DEBUG_LOG)
    time.sleep(1)

    # 运行测试SDK API
    at_write("7\r\n", 3, debug_serial, "OK")
    time.sleep(1)
    at_write("0\r\n", 3, debug_serial, "OK")
    time.sleep(1)
    write_log("开始查询状态", DEBUG_LOG)
    at_write("5\r", 3, debug_serial, "OK")  # 设查询状态
    write_log("查询状态结束", DEBUG_LOG)
    result = at_read(debug_serial, DEBUG_LOG)
    match = re.search(r'modem state is (\w+)', result)
    if match:
        modem_state = match.group(1)
        print(f"modem 重启后的状态为: {modem_state}")
    else:
        print("查询状态失败")
    exit_testsdk(debug_serial,DEBUG_LOG)
    time.sleep(5)
    
    set_at_command('AT+cfun?')   #发送AT+CFUN?指令
    
     # 进入测试接口
    intoTestInterface_testsdk(debug_serial, DEBUG_LOG)
    time.sleep(1)
    # 运行测试SDK API
    at_write("7\r\n", 3, debug_serial, "OK")
    time.sleep(1)
    at_write("0\r\n", 3, debug_serial, "OK")
    time.sleep(1)
    write_log("开始查询IMEI", DEBUG_LOG)
    time.sleep(2)
    at_write("9\r", 3, debug_serial, "OK") 
    write_log("查询IMEI结束", DEBUG_LOG)
    result = at_read(debug_serial, DEBUG_LOG)
    match = re.search(r'imei is (\d+)', result)
    if match:
        imei_number = match.group(1)
        print(f"查询到的IMEI号为: {imei_number}")
    else:
        print("IMEI号获取失败")
    exit_testsdk(debug_serial,DEBUG_LOG)
    time.sleep(3)
    return mcm_ril_servic_PID1, ql_netd_PID1
    
  
def check_pid_changes():
    mcm_ril_servic_PID1, ql_netd_PID1 = modem_reset()
    write_log("##################开始cpu占用率监测##################",DEBUG_LOG)
    check_cpuoccupy()
    time.sleep(2)
    at_write("^C\n",3,debug_serial,"OK")
    at_write("pgrep mcm_ril_servic\r\n", 3, debug_serial, "OK")
    mcm_ril_servic_PID2 = at_read(debug_serial, DEBUG_LOG)
    time.sleep(1)
    at_write("pgrep ql_netd\r\n", 3, debug_serial, "OK")
    ql_netd_PID2 = at_read(debug_serial, DEBUG_LOG)
    time.sleep(1)
    
    if mcm_ril_servic_PID1 != mcm_ril_servic_PID2 and ql_netd_PID1 != ql_netd_PID2:
        write_log("modem reset后对应服务pid有变化 PASS", DEBUG_LOG)
    else:
        write_log("modem reset后对应服务pid一致 FAIL", DEBUG_LOG)
        sys.exit()
  
  
# 检查CPU占用率
def check_cpuoccupy():
    at_write("top -n 10 |grep idle\n",3,debug_serial,"OK")
    Wait_monitor_time = 60
    time.sleep(Wait_monitor_time)
    result = at_read(debug_serial,DEBUG_LOG)
    cpu_idle = result.split("nic ")[1].split("% idle")[0]
    print("持续监测{}秒得到的cpu占用率为:{}".format(Wait_monitor_time,cpu_idle))
    at_write("^C\n",3,debug_serial,"OK")
    if float(cpu_idle) < 20:
      print("cpu占用超过80%")
      sys.exit()

  
if __name__ == '__main__':
    
        check_port_status()
        createLogFile()
        loginDevice()
        time.sleep(5)
        while True:
            writeRuntimesToLog()
            write_log("********************开始执行测试*********************",DEBUG_LOG)
            Serial_front_execution()
            check_pid_changes()
           
